library(nycflights13)
library(tidyverse)
[30m-- [1mAttaching packages[22m --------------------------------------- tidyverse 1.2.1 --[39m
[30m[32mv[30m [34mggplot2[30m 3.0.0 [32mv[30m [34mpurrr [30m 0.2.5
[32mv[30m [34mtibble [30m 1.4.2 [32mv[30m [34mdplyr [30m 0.7.6
[32mv[30m [34mtidyr [30m 0.8.1 [32mv[30m [34mstringr[30m 1.3.1
[32mv[30m [34mreadr [30m 1.1.1 [32mv[30m [34mforcats[30m 0.3.0[39m
[30m-- [1mConflicts[22m ------------------------------------------ tidyverse_conflicts() --
[31mx[30m [34mdplyr[30m::[32mfilter()[30m masks [34mstats[30m::filter()
[31mx[30m [34mdplyr[30m::[32mlag()[30m masks [34mstats[30m::lag()[39m
Filter Rows
# filter by flights on the 1st of january
(jan1 <- filter(flights, month == 1, day == 1))
Comparisons
sqrt(2) ^ 2 == 2
[1] FALSE
1 / 49 * 49 == 1
[1] FALSE
near(sqrt(2) ^ 2, 2)
[1] TRUE
near(1 / 49 * 49, 1)
[1] TRUE
Logical operators
(nov_dec <- filter(flights, month == 11 | month == 12))
# using shorthand
(nov_dec <- filter(flights, month %in% c(11, 12)))
# using demorgan's
(delay_range1 <- filter(flights, !(arr_delay > 120 | dep_delay > 120)))
Missing Values
NA > 5
[1] NA
10 == NA
[1] NA
NA == NA
[1] NA
x <- NA
is.na(x)
[1] TRUE
df <- tibble(x = c(1, NA, 3))
filter(df, x > 1)
filter(df, is.na(x) | x > 1)
Exercises
# 1
filter(flights, arr_delay >= 120)
filter(flights, dest == "IAH" | dest == "HOU")
filter(flights, carrier == "UA" | carrier == "AA" | carrier == "DL")
filter(flights, month %in% c(7, 8, 9))
filter(flights, dep_delay <= 0, arr_delay > 120)
filter(flights, dep_delay >= 60, dep_delay - arr_delay > 30)
filter(flights, between(dep_time, 0, 600) | dep_time == 2400)
filter(flights, is.na(dep_time))
Arrange Rows
arrange(flights, year, month, day)
arrange(flights, desc(dep_delay))
arrange(flights, dep_delay)
# Missing values are always sorted at the end
df <- tibble(x = c(5, 2, NA))
arrange(df, x)
arrange(df, desc(x))
Exercises
# 1
arrange(flights, desc(is.na(dep_time)), dep_time)
# 2
# Most delayed
arrange(flights, desc(dep_delay))
# Earliest
arrange(flights, dep_delay)
# 3
# total air time
arrange(flights, air_time)
# average air time
arrange(flights, distance / air_time * 60)
# 4
# interpretation 1
arrange(flights, desc(distance))
arrange(flights, distance)
# interpretation 2
arrange(flights, desc(air_time))
arrange(flights, air_time)
Select Columns
select(flights, year, month, day)
# Select range of columns
select(flights, year:day)
# Exclude columns
select(flights, -(year:day))
rename(flights, tail_num = tailnum)
# Move some variables to the start of the dataframe
select(flights, time_hour, air_time, everything())
Exercises
# 1
select(flights, dep_time, dep_delay, arr_time, arr_delay)
select(flights, "dep_time", "dep_delay", "arr_time", "arr_delay")
select(flights, starts_with("dep_"), starts_with("arr_"))
select(flights, 4, 6, 7, 9)
select(flights, matches("^(dep|arr)_(delay|time)$"))
of_interest <- c("dep_time", "dep_delay", "arr_time", "arr_delay")
select(flights, one_of(of_interest))
# 2
select(flights, dep_time, dep_time)
# 4
select(flights, contains("TIME"))
select(flights, contains("TIME", ignore.case = FALSE))
Add new variables
(flights_sml <- select(
flights,
year:day,
ends_with("delay"),
distance,
air_time
))
# add some columns
(mutate(
flights_sml,
gain = dep_delay - arr_delay,
speed = distance / air_time * 60
))
# Use new columns for an opperation
(mutate(
flights_sml,
gain = dep_delay - arr_delay,
hours = air_time / 60,
gain_per_hour = gain / hours
))
# Only keep the new variables
(transmute(
flights,
gain = dep_delay - arr_delay,
hours = air_time / 60,
gain_per_hour = gain / hours
))
# Using other functions
(transmute(
flights,
dep_time,
hour = dep_time %/% 100,
minute = dep_time %% 100
))
# Lag and Lead
(x <- 1:10)
[1] 1 2 3 4 5 6 7 8 9 10
lag(x)
[1] NA 1 2 3 4 5 6 7 8 9
lead(x)
[1] 2 3 4 5 6 7 8 9 10 NA
# Running aggregates
cumsum(x)
[1] 1 3 6 10 15 21 28 36 45 55
cummean(x)
[1] 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5
# Ranking
y <- c(2, 3, 3, NA, 4, 7)
min_rank(y)
[1] 1 2 2 NA 4 5
min_rank(desc(y))
[1] 5 3 3 NA 2 1
row_number(y)
[1] 1 2 3 NA 4 5
dense_rank(y)
[1] 1 2 2 NA 3 4
cume_dist(y)
[1] 0.2 0.6 0.6 NA 0.8 1.0
Exercises
# 1
# Midnight is represented as 2400 -> 24 * 60 = 1440 minutes after midnight (need to account for this)
time_to_mins <- function(t) {
return((t %/% 100 * 60 + t %% 100) %% 1440)
}
(flight_times <- mutate(
flights,
dep_time_mins = time_to_mins(dep_time),
sched_dep_time_mins = time_to_mins(sched_dep_time)
))
select(flight_times, dep_time, sched_dep_time, dep_time_mins, sched_dep_time_mins)
# 2
# Grab rows of interest
(flight_durs <- select(flights, arr_time, dep_time, air_time, origin, dest))
# Convert them all to minutes (except air time, which already is)
(flight_durs <- mutate(
flight_durs,
arr_time_mins = time_to_mins(arr_time),
dep_time_mins = time_to_mins(dep_time)
))
# Rearrange columns
flight_durs <- select(flight_durs, origin, dest, air_time, everything())
# Calculate air_time_diff
(flight_durs <- mutate(flight_durs, air_time_diff = arr_time_mins - dep_time_mins))
# Check if it worked. Are there negatives?
arrange(flight_durs, air_time_diff)
# There are, so flights that go overnight are incorrect. Also, timezones could cause problems
# 3
# SHould be difference between dep time and scheduled dep time
flights_deptime <-
mutate(
flights,
dep_time_mins = time_to_mins(dep_time),
sched_dep_time_mins = time_to_mins(sched_dep_time),
dep_delay_mins = dep_time_mins - sched_dep_time_mins
)
# Have same issue that overnight delays appear as <= 0
Exercises (cont.)
# 4
(most_delayed <- select(
mutate(
flights,
dep_delay_rank = min_rank(desc(dep_delay))
),
dep_delay_rank,
dep_delay,
everything()
)
)
arrange(most_delayed, dep_delay)
# Only grab the 50 most delayed (there are no repeats in the top 10)
(top_50 <- arrange(
filter(most_delayed, dep_delay_rank <= 50),
dep_delay_rank)
)
# 5
1:3 + 1:10
longer object length is not a multiple of shorter object length
[1] 2 4 6 5 7 9 8 10 12 11
Grouped Summaries
summarise(flights, delay = mean(dep_delay, na.rm = TRUE))
by_day <- group_by(flights, year, month, day)
summarize(by_day, delay = mean(dep_delay, na.rm = TRUE))
# Group flights by destination
by_dest <- group_by(flights, dest)
# Summarize distance, avg. delay, number of flights
(delays <- summarize(
by_dest,
count = n(),
dist = mean(distance, na.rm = TRUE),
delay = mean(arr_delay, na.rm = TRUE)
))
# Honolulu is quite far away from all others
arrange(delays, desc(dist))
# Ignore destinations that rarely occur
arrange(delays, count)
# Filter to remove noise (I.E. Honolulu and destinations with a very small number of flights)
(delays <- filter(delays, count > 20, dest != "HNL"))
# Visualize the data
ggplot(data = delays, mapping = aes(x = dist, y = delay)) +
geom_point(aes(size = count), alpha = 1/3) +
geom_smooth(se = FALSE)

# Do the same thing using pipes
# Note: x %>% f(y) == f(x, y) and x %>% f(y) %>% g(z) == g(f(x, y), z)
(delays <- flights %>%
group_by(dest) %>%
summarize(
count = n(),
dist = mean(distance, na.rm = TRUE),
delay = mean(arr_delay, na.rm = TRUE)
) %>%
filter(count > 20, dest != "HNL") %>%
arrange(desc(delay))
)
# Reason for using na.rm
flights %>%
group_by(year, month, day) %>%
summarize(mean = mean(dep_delay))
# Fixed
flights %>%
group_by(year, month, day) %>%
summarize(mean = mean(dep_delay, na.rm = TRUE))
# Remove cancelled flights from the data set
not_cancelled <- flights %>%
filter(!is.na(dep_delay), !is.na(arr_delay))
not_cancelled %>%
group_by(year, month, day) %>%
summarize(mean = mean(dep_delay))
Grouped Summaries (cont.)
# Find individual planes (identified by tail num) and their average delays
delays <- not_cancelled %>%
group_by(tailnum) %>%
summarize(
delay = mean(arr_delay)
)
ggplot(data = delays, mapping = aes(x = delay)) +
geom_freqpoly(binwidth = 10)

# Try with number of flights vs avg delay
delays <- not_cancelled %>%
group_by(tailnum) %>%
summarize(
delay = mean(arr_delay),
n = n()
)
ggplot(data = delays, mapping = aes(x = n, y = delay)) +
geom_point(alpha = 1/10)

LS0tDQp0aXRsZTogIkNoYXB0ZXIgNSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCg0KYGBge3J9DQpsaWJyYXJ5KG55Y2ZsaWdodHMxMykNCmxpYnJhcnkodGlkeXZlcnNlKQ0KYGBgDQoNCiMgbnljZmxpZ2h0czEzDQpgYGB7cn0NCmZsaWdodHMNCmBgYA0KDQojIEZpbHRlciBSb3dzDQpgYGB7cn0NCiMgZmlsdGVyIGJ5IGZsaWdodHMgb24gdGhlIDFzdCBvZiBqYW51YXJ5DQooamFuMSA8LSBmaWx0ZXIoZmxpZ2h0cywgbW9udGggPT0gMSwgZGF5ID09IDEpKQ0KYGBgDQoNCiMgQ29tcGFyaXNvbnMNCmBgYHtyfQ0Kc3FydCgyKSBeIDIgPT0gMg0KMSAvIDQ5ICogNDkgPT0gMQ0KbmVhcihzcXJ0KDIpIF4gMiwgMikNCm5lYXIoMSAvIDQ5ICogNDksIDEpDQoNCmBgYA0KDQojIExvZ2ljYWwgb3BlcmF0b3JzDQpgYGB7cn0NCihub3ZfZGVjIDwtIGZpbHRlcihmbGlnaHRzLCBtb250aCA9PSAxMSB8IG1vbnRoID09IDEyKSkNCg0KIyB1c2luZyBzaG9ydGhhbmQNCihub3ZfZGVjIDwtIGZpbHRlcihmbGlnaHRzLCBtb250aCAlaW4lIGMoMTEsIDEyKSkpDQojIHVzaW5nIGRlbW9yZ2FuJ3MNCihkZWxheV9yYW5nZTEgPC0gZmlsdGVyKGZsaWdodHMsICEoYXJyX2RlbGF5ID4gMTIwIHwgZGVwX2RlbGF5ID4gMTIwKSkpDQpgYGANCg0KIyBNaXNzaW5nIFZhbHVlcw0KYGBge3J9DQpOQSA+IDUNCjEwID09IE5BDQpOQSA9PSBOQQ0KeCA8LSBOQQ0KaXMubmEoeCkNCmRmIDwtIHRpYmJsZSh4ID0gYygxLCBOQSwgMykpDQpmaWx0ZXIoZGYsIHggPiAxKQ0KZmlsdGVyKGRmLCBpcy5uYSh4KSB8IHggPiAxKQ0KYGBgDQoNCiMgRXhlcmNpc2VzDQpgYGB7cn0NCiMgMQ0KZmlsdGVyKGZsaWdodHMsIGFycl9kZWxheSA+PSAxMjApDQpmaWx0ZXIoZmxpZ2h0cywgZGVzdCA9PSAiSUFIIiB8IGRlc3QgPT0gIkhPVSIpDQpmaWx0ZXIoZmxpZ2h0cywgY2FycmllciA9PSAiVUEiIHwgY2FycmllciA9PSAiQUEiIHwgY2FycmllciA9PSAiREwiKQ0KZmlsdGVyKGZsaWdodHMsIG1vbnRoICVpbiUgYyg3LCA4LCA5KSkNCmZpbHRlcihmbGlnaHRzLCBkZXBfZGVsYXkgPD0gMCwgYXJyX2RlbGF5ID4gMTIwKQ0KZmlsdGVyKGZsaWdodHMsIGRlcF9kZWxheSA+PSA2MCwgZGVwX2RlbGF5IC0gYXJyX2RlbGF5ID4gMzApDQpmaWx0ZXIoZmxpZ2h0cywgYmV0d2VlbihkZXBfdGltZSwgMCwgNjAwKSB8IGRlcF90aW1lID09IDI0MDApDQpmaWx0ZXIoZmxpZ2h0cywgaXMubmEoZGVwX3RpbWUpKQ0KYGBgDQoNCiMgQXJyYW5nZSBSb3dzDQpgYGB7cn0NCmFycmFuZ2UoZmxpZ2h0cywgeWVhciwgbW9udGgsIGRheSkNCmFycmFuZ2UoZmxpZ2h0cywgZGVzYyhkZXBfZGVsYXkpKQ0KYXJyYW5nZShmbGlnaHRzLCBkZXBfZGVsYXkpDQoNCiMgTWlzc2luZyB2YWx1ZXMgYXJlIGFsd2F5cyBzb3J0ZWQgYXQgdGhlIGVuZA0KZGYgPC0gdGliYmxlKHggPSBjKDUsIDIsIE5BKSkNCmFycmFuZ2UoZGYsIHgpDQphcnJhbmdlKGRmLCBkZXNjKHgpKQ0KYGBgDQoNCiMgRXhlcmNpc2VzDQpgYGB7cn0NCiMgMQ0KYXJyYW5nZShmbGlnaHRzLCBkZXNjKGlzLm5hKGRlcF90aW1lKSksIGRlcF90aW1lKQ0KIyAyDQojIE1vc3QgZGVsYXllZA0KYXJyYW5nZShmbGlnaHRzLCBkZXNjKGRlcF9kZWxheSkpDQojIEVhcmxpZXN0DQphcnJhbmdlKGZsaWdodHMsIGRlcF9kZWxheSkNCiMgMw0KIyB0b3RhbCBhaXIgdGltZQ0KYXJyYW5nZShmbGlnaHRzLCBhaXJfdGltZSkNCiMgYXZlcmFnZSBhaXIgdGltZQ0KYXJyYW5nZShmbGlnaHRzLCBkaXN0YW5jZSAvIGFpcl90aW1lICogNjApDQojIDQNCiMgaW50ZXJwcmV0YXRpb24gMQ0KYXJyYW5nZShmbGlnaHRzLCBkZXNjKGRpc3RhbmNlKSkNCmFycmFuZ2UoZmxpZ2h0cywgZGlzdGFuY2UpDQojIGludGVycHJldGF0aW9uIDINCmFycmFuZ2UoZmxpZ2h0cywgZGVzYyhhaXJfdGltZSkpDQphcnJhbmdlKGZsaWdodHMsIGFpcl90aW1lKQ0KYGBgDQoNCiMgU2VsZWN0IENvbHVtbnMNCmBgYHtyfQ0Kc2VsZWN0KGZsaWdodHMsIHllYXIsIG1vbnRoLCBkYXkpDQojIFNlbGVjdCByYW5nZSBvZiBjb2x1bW5zDQpzZWxlY3QoZmxpZ2h0cywgeWVhcjpkYXkpDQojIEV4Y2x1ZGUgY29sdW1ucw0Kc2VsZWN0KGZsaWdodHMsIC0oeWVhcjpkYXkpKQ0KcmVuYW1lKGZsaWdodHMsIHRhaWxfbnVtID0gdGFpbG51bSkNCiMgTW92ZSBzb21lIHZhcmlhYmxlcyB0byB0aGUgc3RhcnQgb2YgdGhlIGRhdGFmcmFtZQ0Kc2VsZWN0KGZsaWdodHMsIHRpbWVfaG91ciwgYWlyX3RpbWUsIGV2ZXJ5dGhpbmcoKSkNCmBgYA0KDQojIEV4ZXJjaXNlcw0KYGBge3J9DQojIDENCnNlbGVjdChmbGlnaHRzLCBkZXBfdGltZSwgZGVwX2RlbGF5LCBhcnJfdGltZSwgYXJyX2RlbGF5KQ0Kc2VsZWN0KGZsaWdodHMsICJkZXBfdGltZSIsICJkZXBfZGVsYXkiLCAiYXJyX3RpbWUiLCAiYXJyX2RlbGF5IikNCnNlbGVjdChmbGlnaHRzLCBzdGFydHNfd2l0aCgiZGVwXyIpLCBzdGFydHNfd2l0aCgiYXJyXyIpKQ0Kc2VsZWN0KGZsaWdodHMsIDQsIDYsIDcsIDkpDQpzZWxlY3QoZmxpZ2h0cywgbWF0Y2hlcygiXihkZXB8YXJyKV8oZGVsYXl8dGltZSkkIikpDQpvZl9pbnRlcmVzdCA8LSBjKCJkZXBfdGltZSIsICJkZXBfZGVsYXkiLCAiYXJyX3RpbWUiLCAiYXJyX2RlbGF5IikNCnNlbGVjdChmbGlnaHRzLCBvbmVfb2Yob2ZfaW50ZXJlc3QpKQ0KIyAyDQpzZWxlY3QoZmxpZ2h0cywgZGVwX3RpbWUsIGRlcF90aW1lKQ0KDQojIDQNCnNlbGVjdChmbGlnaHRzLCBjb250YWlucygiVElNRSIpKQ0Kc2VsZWN0KGZsaWdodHMsIGNvbnRhaW5zKCJUSU1FIiwgaWdub3JlLmNhc2UgPSBGQUxTRSkpDQpgYGANCg0KIyBBZGQgbmV3IHZhcmlhYmxlcw0KYGBge3J9DQooZmxpZ2h0c19zbWwgPC0gc2VsZWN0KA0KICBmbGlnaHRzLA0KICB5ZWFyOmRheSwNCiAgZW5kc193aXRoKCJkZWxheSIpLA0KICBkaXN0YW5jZSwNCiAgYWlyX3RpbWUNCikpDQoNCiMgYWRkIHNvbWUgY29sdW1ucw0KKG11dGF0ZSgNCiAgZmxpZ2h0c19zbWwsDQogIGdhaW4gPSBkZXBfZGVsYXkgLSBhcnJfZGVsYXksDQogIHNwZWVkID0gZGlzdGFuY2UgLyBhaXJfdGltZSAqIDYwDQopKQ0KDQojIFVzZSBuZXcgY29sdW1ucyBmb3IgYW4gb3BwZXJhdGlvbg0KKG11dGF0ZSgNCiAgZmxpZ2h0c19zbWwsDQogIGdhaW4gPSBkZXBfZGVsYXkgLSBhcnJfZGVsYXksDQogIGhvdXJzID0gYWlyX3RpbWUgLyA2MCwNCiAgZ2Fpbl9wZXJfaG91ciA9IGdhaW4gLyBob3Vycw0KKSkNCg0KIyBPbmx5IGtlZXAgdGhlIG5ldyB2YXJpYWJsZXMNCih0cmFuc211dGUoDQogIGZsaWdodHMsDQogIGdhaW4gPSBkZXBfZGVsYXkgLSBhcnJfZGVsYXksDQogIGhvdXJzID0gYWlyX3RpbWUgLyA2MCwNCiAgZ2Fpbl9wZXJfaG91ciA9IGdhaW4gLyBob3Vycw0KKSkNCg0KIyBVc2luZyBvdGhlciBmdW5jdGlvbnMNCih0cmFuc211dGUoDQogIGZsaWdodHMsDQogIGRlcF90aW1lLA0KICBob3VyID0gZGVwX3RpbWUgJS8lIDEwMCwNCiAgbWludXRlID0gZGVwX3RpbWUgJSUgMTAwDQopKQ0KDQojIExhZyBhbmQgTGVhZA0KKHggPC0gMToxMCkNCmxhZyh4KQ0KbGVhZCh4KQ0KDQojIFJ1bm5pbmcgYWdncmVnYXRlcw0KY3Vtc3VtKHgpDQpjdW1tZWFuKHgpDQoNCiMgUmFua2luZw0KeSA8LSBjKDIsIDMsIDMsIE5BLCA0LCA3KQ0KbWluX3JhbmsoeSkNCm1pbl9yYW5rKGRlc2MoeSkpDQpyb3dfbnVtYmVyKHkpDQpkZW5zZV9yYW5rKHkpDQpjdW1lX2Rpc3QoeSkNCmBgYA0KDQojIEV4ZXJjaXNlcw0KYGBge3J9DQojIDENCiMgTWlkbmlnaHQgaXMgcmVwcmVzZW50ZWQgYXMgMjQwMCAtPiAyNCAqIDYwID0gMTQ0MCBtaW51dGVzIGFmdGVyIG1pZG5pZ2h0IChuZWVkIHRvIGFjY291bnQgZm9yIHRoaXMpDQp0aW1lX3RvX21pbnMgPC0gZnVuY3Rpb24odCkgew0KICByZXR1cm4oKHQgJS8lIDEwMCAqIDYwICsgdCAlJSAxMDApICUlIDE0NDApDQp9DQoNCihmbGlnaHRfdGltZXMgPC0gbXV0YXRlKA0KICBmbGlnaHRzLA0KICBkZXBfdGltZV9taW5zID0gdGltZV90b19taW5zKGRlcF90aW1lKSwNCiAgc2NoZWRfZGVwX3RpbWVfbWlucyA9IHRpbWVfdG9fbWlucyhzY2hlZF9kZXBfdGltZSkNCikpDQoNCnNlbGVjdChmbGlnaHRfdGltZXMsIGRlcF90aW1lLCBzY2hlZF9kZXBfdGltZSwgZGVwX3RpbWVfbWlucywgc2NoZWRfZGVwX3RpbWVfbWlucykNCg0KIyAyDQojIEdyYWIgcm93cyBvZiBpbnRlcmVzdA0KKGZsaWdodF9kdXJzIDwtIHNlbGVjdChmbGlnaHRzLCBhcnJfdGltZSwgZGVwX3RpbWUsIGFpcl90aW1lLCBvcmlnaW4sIGRlc3QpKQ0KIyBDb252ZXJ0IHRoZW0gYWxsIHRvIG1pbnV0ZXMgKGV4Y2VwdCBhaXIgdGltZSwgd2hpY2ggYWxyZWFkeSBpcykNCihmbGlnaHRfZHVycyA8LSBtdXRhdGUoDQogIGZsaWdodF9kdXJzLA0KICBhcnJfdGltZV9taW5zID0gdGltZV90b19taW5zKGFycl90aW1lKSwNCiAgZGVwX3RpbWVfbWlucyA9IHRpbWVfdG9fbWlucyhkZXBfdGltZSkNCikpDQojIFJlYXJyYW5nZSBjb2x1bW5zDQpmbGlnaHRfZHVycyA8LSBzZWxlY3QoZmxpZ2h0X2R1cnMsIG9yaWdpbiwgZGVzdCwgYWlyX3RpbWUsIGV2ZXJ5dGhpbmcoKSkNCiMgQ2FsY3VsYXRlIGFpcl90aW1lX2RpZmYNCihmbGlnaHRfZHVycyA8LSBtdXRhdGUoZmxpZ2h0X2R1cnMsIGFpcl90aW1lX2RpZmYgPSBhcnJfdGltZV9taW5zIC0gZGVwX3RpbWVfbWlucykpDQojIENoZWNrIGlmIGl0IHdvcmtlZC4gQXJlIHRoZXJlIG5lZ2F0aXZlcz8NCmFycmFuZ2UoZmxpZ2h0X2R1cnMsIGFpcl90aW1lX2RpZmYpDQojIFRoZXJlIGFyZSwgc28gZmxpZ2h0cyB0aGF0IGdvIG92ZXJuaWdodCBhcmUgaW5jb3JyZWN0LiBBbHNvLCB0aW1lem9uZXMgY291bGQgY2F1c2UgcHJvYmxlbXMNCg0KIyAzDQojIFNIb3VsZCBiZSBkaWZmZXJlbmNlIGJldHdlZW4gZGVwIHRpbWUgYW5kIHNjaGVkdWxlZCBkZXAgdGltZQ0KZmxpZ2h0c19kZXB0aW1lIDwtIA0KICBtdXRhdGUoDQogICAgZmxpZ2h0cywNCiAgICBkZXBfdGltZV9taW5zID0gdGltZV90b19taW5zKGRlcF90aW1lKSwNCiAgICBzY2hlZF9kZXBfdGltZV9taW5zID0gdGltZV90b19taW5zKHNjaGVkX2RlcF90aW1lKSwNCiAgICBkZXBfZGVsYXlfbWlucyA9IGRlcF90aW1lX21pbnMgLSBzY2hlZF9kZXBfdGltZV9taW5zDQogICkNCiMgSGF2ZSBzYW1lIGlzc3VlIHRoYXQgb3Zlcm5pZ2h0IGRlbGF5cyBhcHBlYXIgYXMgPD0gMA0KYGBgDQoNCiMgRXhlcmNpc2VzIChjb250LikNCmBgYHtyfQ0KIyA0DQoobW9zdF9kZWxheWVkIDwtIHNlbGVjdCgNCiAgbXV0YXRlKA0KICAgIGZsaWdodHMsDQogICAgZGVwX2RlbGF5X3JhbmsgPSBtaW5fcmFuayhkZXNjKGRlcF9kZWxheSkpDQogICksDQogIGRlcF9kZWxheV9yYW5rLA0KICBkZXBfZGVsYXksDQogIGV2ZXJ5dGhpbmcoKQ0KICApDQogKQ0KYXJyYW5nZShtb3N0X2RlbGF5ZWQsIGRlcF9kZWxheSkNCiMgT25seSBncmFiIHRoZSA1MCBtb3N0IGRlbGF5ZWQgKHRoZXJlIGFyZSBubyByZXBlYXRzIGluIHRoZSB0b3AgMTApDQoodG9wXzUwIDwtIGFycmFuZ2UoDQogIGZpbHRlcihtb3N0X2RlbGF5ZWQsIGRlcF9kZWxheV9yYW5rIDw9IDUwKSwNCiAgZGVwX2RlbGF5X3JhbmspDQopDQoNCiMgNQ0KMTozICsgMToxMA0KIyBrZWVwcyBjeWNsaW5nIDE6MyB1bnRpbCByZWFjaCAxMA0KYGBgDQoNCiMgR3JvdXBlZCBTdW1tYXJpZXMNCmBgYHtyfQ0Kc3VtbWFyaXNlKGZsaWdodHMsIGRlbGF5ID0gbWVhbihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSkpDQpieV9kYXkgPC0gZ3JvdXBfYnkoZmxpZ2h0cywgeWVhciwgbW9udGgsIGRheSkNCnN1bW1hcml6ZShieV9kYXksIGRlbGF5ID0gbWVhbihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSkpDQoNCiMgR3JvdXAgZmxpZ2h0cyBieSBkZXN0aW5hdGlvbg0KYnlfZGVzdCA8LSBncm91cF9ieShmbGlnaHRzLCBkZXN0KQ0KIyBTdW1tYXJpemUgZGlzdGFuY2UsIGF2Zy4gZGVsYXksIG51bWJlciBvZiBmbGlnaHRzDQooZGVsYXlzIDwtIHN1bW1hcml6ZSgNCiAgYnlfZGVzdCwNCiAgY291bnQgPSBuKCksDQogIGRpc3QgPSBtZWFuKGRpc3RhbmNlLCBuYS5ybSA9IFRSVUUpLA0KICBkZWxheSA9IG1lYW4oYXJyX2RlbGF5LCBuYS5ybSA9IFRSVUUpDQopKQ0KIyBIb25vbHVsdSBpcyBxdWl0ZSBmYXIgYXdheSBmcm9tIGFsbCBvdGhlcnMNCmFycmFuZ2UoZGVsYXlzLCBkZXNjKGRpc3QpKQ0KIyBJZ25vcmUgZGVzdGluYXRpb25zIHRoYXQgcmFyZWx5IG9jY3VyDQphcnJhbmdlKGRlbGF5cywgY291bnQpDQojIEZpbHRlciB0byByZW1vdmUgbm9pc2UgKEkuRS4gSG9ub2x1bHUgYW5kIGRlc3RpbmF0aW9ucyB3aXRoIGEgdmVyeSBzbWFsbCBudW1iZXIgb2YgZmxpZ2h0cykNCihkZWxheXMgPC0gZmlsdGVyKGRlbGF5cywgY291bnQgPiAyMCwgZGVzdCAhPSAiSE5MIikpDQoNCiMgVmlzdWFsaXplIHRoZSBkYXRhDQpnZ3Bsb3QoZGF0YSA9IGRlbGF5cywgbWFwcGluZyA9IGFlcyh4ID0gZGlzdCwgeSA9IGRlbGF5KSkgKw0KICBnZW9tX3BvaW50KGFlcyhzaXplID0gY291bnQpLCBhbHBoYSA9IDEvMykgKw0KICBnZW9tX3Ntb290aChzZSA9IEZBTFNFKQ0KDQojIERvIHRoZSBzYW1lIHRoaW5nIHVzaW5nIHBpcGVzDQojIE5vdGU6IHggJT4lIGYoeSkgPT0gZih4LCB5KSBhbmQgeCAlPiUgZih5KSAlPiUgZyh6KSA9PSBnKGYoeCwgeSksIHopDQooZGVsYXlzIDwtIGZsaWdodHMgJT4lDQogIGdyb3VwX2J5KGRlc3QpICU+JQ0KICBzdW1tYXJpemUoDQogICAgY291bnQgPSBuKCksDQogICAgZGlzdCA9IG1lYW4oZGlzdGFuY2UsIG5hLnJtID0gVFJVRSksDQogICAgZGVsYXkgPSBtZWFuKGFycl9kZWxheSwgbmEucm0gPSBUUlVFKQ0KICApICU+JQ0KICBmaWx0ZXIoY291bnQgPiAyMCwgZGVzdCAhPSAiSE5MIikgJT4lDQogIGFycmFuZ2UoZGVzYyhkZWxheSkpDQopDQoNCiMgUmVhc29uIGZvciB1c2luZyBuYS5ybQ0KZmxpZ2h0cyAlPiUNCiAgZ3JvdXBfYnkoeWVhciwgbW9udGgsIGRheSkgJT4lDQogIHN1bW1hcml6ZShtZWFuID0gbWVhbihkZXBfZGVsYXkpKQ0KIyBGaXhlZA0KZmxpZ2h0cyAlPiUNCiAgZ3JvdXBfYnkoeWVhciwgbW9udGgsIGRheSkgJT4lDQogIHN1bW1hcml6ZShtZWFuID0gbWVhbihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSkpDQoNCiMgUmVtb3ZlIGNhbmNlbGxlZCBmbGlnaHRzIGZyb20gdGhlIGRhdGEgc2V0DQpub3RfY2FuY2VsbGVkIDwtIGZsaWdodHMgJT4lDQogIGZpbHRlcighaXMubmEoZGVwX2RlbGF5KSwgIWlzLm5hKGFycl9kZWxheSkpDQoNCm5vdF9jYW5jZWxsZWQgJT4lDQogIGdyb3VwX2J5KHllYXIsIG1vbnRoLCBkYXkpICU+JQ0KICBzdW1tYXJpemUobWVhbiA9IG1lYW4oZGVwX2RlbGF5KSkNCmBgYA0KDQojIEdyb3VwZWQgU3VtbWFyaWVzIChjb250LikNCmBgYHtyfQ0KIyBGaW5kIGluZGl2aWR1YWwgcGxhbmVzIChpZGVudGlmaWVkIGJ5IHRhaWwgbnVtKSBhbmQgdGhlaXIgYXZlcmFnZSBkZWxheXMNCmRlbGF5cyA8LSBub3RfY2FuY2VsbGVkICU+JQ0KICBncm91cF9ieSh0YWlsbnVtKSAlPiUNCiAgc3VtbWFyaXplKA0KICAgIGRlbGF5ID0gbWVhbihhcnJfZGVsYXkpDQogICkNCg0KZ2dwbG90KGRhdGEgPSBkZWxheXMsIG1hcHBpbmcgPSBhZXMoeCA9IGRlbGF5KSkgKw0KICBnZW9tX2ZyZXFwb2x5KGJpbndpZHRoID0gMTApDQoNCiMgVHJ5IHdpdGggbnVtYmVyIG9mIGZsaWdodHMgdnMgYXZnIGRlbGF5DQpkZWxheXMgPC0gbm90X2NhbmNlbGxlZCAlPiUNCiAgZ3JvdXBfYnkodGFpbG51bSkgJT4lDQogIHN1bW1hcml6ZSgNCiAgICBkZWxheSA9IG1lYW4oYXJyX2RlbGF5KSwNCiAgICBuID0gbigpDQogICkNCg0KIyBXZSBzZWUgdGhhdCB2YXJpYXRpb24gZGVjcmVhc2VzIGFzIHNhbXBsZSBzaXplIGluY3JlYXNlcw0KZ2dwbG90KGRhdGEgPSBkZWxheXMsIG1hcHBpbmcgPSBhZXMoeCA9IG4sIHkgPSBkZWxheSkpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDEvMTApDQpgYGANCg0K